package service;

import model.Student;
import model.StudentProfile;
import utils.DatabaseUtil;

import javax.swing.JOptionPane;
import utils.PasswordUtil;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class StudentService {

    /**
     * 获取所有学生的信息，包括学号、姓名、性别、身份证、家庭地址等，并关联班级名称、专业名称和院系名称。
     *
     * @return 学生列表
     */
    public List<Student> getAllStudents() {
        List<Student> students = new ArrayList<>();  // 创建一个空的学生列表用于存储查询结果
        String sql = "SELECT s.*, c.class_name, m.major_name, d.dept_name, " +
                "u.name as user_name " +
                "FROM students s " +
                "LEFT JOIN classes c ON s.class_id = c.id " +
                "LEFT JOIN majors m ON c.major_code = m.major_code " +
                "LEFT JOIN departments d ON m.dept_code = d.dept_code " +
                "LEFT JOIN users u ON s.user_id = u.id " +
                "ORDER BY s.student_no";  // SQL查询语句，从students表中查询所有学生信息，并按学号排序

        try (Connection conn = DatabaseUtil.getConnection();  // 获取数据库连接
             Statement stmt = conn.createStatement();  // 创建Statement对象用于执行SQL语句
             ResultSet rs = stmt.executeQuery(sql)) {  // 执行查询语句并获取结果集

            while (rs.next()) {  // 遍历查询结果中的每一行
                Student student = new Student();  // 创建一个新的Student对象用于存储当前行的数据

                // 将结果集中的每一列数据设置到Student对象中
                student.setId(rs.getInt("id"));
                student.setUserId(rs.getInt("user_id"));
                student.setStudentNo(rs.getString("student_no"));
                student.setName(rs.getString("name"));
                student.setGender(rs.getString("gender"));
                student.setIdCard(rs.getString("id_card"));
                student.setHomeAddress(rs.getString("home_address"));

                // 如果class_id不为null，则设置class_id，否则设置为0
                Object classIdObj = rs.getObject("class_id");
                student.setClassId(classIdObj != null ? rs.getInt("class_id") : 0);

                student.setClassName(rs.getString("class_name"));
                student.setMajorName(rs.getString("major_name"));
                student.setDepartmentName(rs.getString("dept_name"));
                student.setEnrollmentYear(rs.getInt("enrollment_year"));
                student.setPhone(rs.getString("phone"));
                student.setEmail(rs.getString("email"));
                student.setStatus(rs.getString("status"));
                student.setBirthDate(rs.getDate("birth_date"));
                student.setCreatedAt(rs.getTimestamp("created_at"));

                students.add(student);  // 将填充好的Student对象添加到学生列表中
            }
        } catch (SQLException e) {
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
        }
        return students;  // 返回查询到的学生列表
    }

    /**
     * 根据用户ID获取学生的信息，包括学号、姓名、性别、班级名称等。
     *
     * @param userId 用户ID
     * @return 学生信息对象，如果未找到则返回null
     */
    public StudentProfile getStudentByUserId(int userId) {
        String sql = "SELECT s.*, c.class_name FROM students s " +
                "LEFT JOIN classes c ON s.class_id = c.id " +
                "WHERE s.user_id = ?";  // SQL查询语句，根据user_id从students表中获取学生信息，并关联班级名称

        try (Connection conn = DatabaseUtil.getConnection();  // 获取数据库连接
             PreparedStatement stmt = conn.prepareStatement(sql)) {  // 创建PreparedStatement对象用于执行SQL语句

            stmt.setInt(1, userId);  // 设置SQL语句中的参数user_id
            ResultSet rs = stmt.executeQuery();  // 执行查询语句并获取结果集

            if (rs.next()) {  // 如果查询结果中有一行数据
                StudentProfile student = new StudentProfile();  // 创建一个新的StudentProfile对象用于存储当前行的数据

                // 将结果集中的每一列数据设置到StudentProfile对象中
                student.setId(rs.getInt("id"));
                student.setStudentNo(rs.getString("student_no"));
                student.setName(rs.getString("name"));
                student.setGender(rs.getString("gender"));
                student.setClassName(rs.getString("class_name"));

                // 如果class_id不为null，则设置classNo，否则设置为null
                Object classIdObj = rs.getObject("class_id");
                student.setClassNo(classIdObj != null ? ((Number)classIdObj).intValue() : null);

                student.setEnrollmentYear(rs.getInt("enrollment_year"));
                student.setPhone(rs.getString("phone"));
                student.setEmail(rs.getString("email"));
                student.setStatus(rs.getString("status"));

                return student;  // 返回填充好的StudentProfile对象
            }
        } catch (SQLException e) {
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
        }
        return null;  // 如果未找到学生信息，则返回null
    }

    /**
     * 创建一个新学生，并为其生成一个用户账号和初始密码。
     *
     * @param student 学生对象，包含学生的基本信息
     * @return 如果创建成功则返回true，否则返回false
     */
    public boolean createStudent(Student student) {
        Connection conn = null;
        try {
            conn = DatabaseUtil.getConnection();  // 获取数据库连接
            conn.setAutoCommit(false);  // 关闭自动提交，开启事务

            // 1. 创建用户账号
            String userSql = "INSERT INTO users (username, password, role, name, gender, phone, email, status) " +
                    "VALUES (?, ?, 'STUDENT', ?, ?, ?, ?, 1)";  // SQL插入语句，向users表中插入新用户信息，角色为'STUDENT'

            // 生成密码（身份证后6位）
            String password = student.getIdCard().substring(student.getIdCard().length() - 6);
            // 加密密码
            String encryptedPassword = PasswordUtil.encrypt(password);  // 使用PasswordUtil工具类对密码进行加密

            try (PreparedStatement pstmt = conn.prepareStatement(userSql, Statement.RETURN_GENERATED_KEYS)) {  // 创建PreparedStatement对象用于执行SQL语句
                pstmt.setString(1, student.getStudentNo());  // 设置SQL语句中的参数username为学生的学号
                pstmt.setString(2, encryptedPassword);  // 设置SQL语句中的参数password为加密后的密码
                pstmt.setString(3, student.getName());  // 设置SQL语句中的参数name为学生的姓名
                pstmt.setString(4, student.getGender());  // 设置SQL语句中的参数gender为学生的性别
                pstmt.setString(5, student.getPhone());  // 设置SQL语句中的参数phone为学生的电话
                pstmt.setString(6, student.getEmail());  // 设置SQL语句中的参数email为学生的邮箱

                if (pstmt.executeUpdate() > 0) {  // 执行插入语句并检查受影响的行数
                    // 获取新创建的用户ID
                    ResultSet rs = pstmt.getGeneratedKeys();  // 获取插入后生成的主键（用户ID）
                    if (rs.next()) {
                        int userId = rs.getInt(1);  // 获取用户ID

                        // 2. 创建学生记录
                        String studentSql = "INSERT INTO students (user_id, student_no, name, id_card, " +
                                "gender, class_id, enrollment_year, phone, email, birth_date, " +
                                "home_address, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";  // SQL插入语句，向students表中插入新学生信息

                        try (PreparedStatement stmt = conn.prepareStatement(studentSql)) {  // 创建PreparedStatement对象用于执行SQL语句
                            stmt.setInt(1, userId);  // 设置SQL语句中的参数user_id为新创建的用户ID
                            stmt.setString(2, student.getStudentNo());  // 设置SQL语句中的参数student_no为学生的学号
                            stmt.setString(3, student.getName());  // 设置SQL语句中的参数name为学生的姓名
                            stmt.setString(4, student.getIdCard());  // 设置SQL语句中的参数id_card为学生的身份证号码
                            stmt.setString(5, student.getGender());  // 设置SQL语句中的参数gender为学生的性别
                            stmt.setInt(6, student.getClassId());  // 确保设置班级ID
                            stmt.setInt(7, student.getEnrollmentYear());  // 设置SQL语句中的参数enrollment_year为入学年份
                            stmt.setString(8, student.getPhone());  // 设置SQL语句中的参数phone为学生的电话
                            stmt.setString(9, student.getEmail());  // 设置SQL语句中的参数email为学生的邮箱
                            java.sql.Date sqlBirthDate = new java.sql.Date(student.getBirthDate().getTime());  // 将java.util.Date转换为java.sql.Date
                            stmt.setDate(10, sqlBirthDate);  // 设置SQL语句中的参数birth_date为学生的出生日期
                            stmt.setString(11, student.getHomeAddress());  // 设置SQL语句中的参数home_address为学生的家庭地址
                            stmt.setString(12, "在读");  // 设置默认状态为"在读"

                            if (stmt.executeUpdate() > 0) {  // 执行插入语句并检查受影响的行数
                                conn.commit();  // 如果插入成功，则提交事务
                                // 显示账号信息
                                JOptionPane.showMessageDialog(null,
                                        "学生添加成功！\n" +
                                                "账号：" + student.getStudentNo() + "\n" +
                                                "初始密码：" + password + "\n" +
                                                "请提醒学生及时修改密码！",
                                        "创建成功",
                                        JOptionPane.INFORMATION_MESSAGE);  // 弹出对话框显示创建成功信息
                                return true;
                            }
                        }
                    }
                }
            }

            conn.rollback();  // 如果插入失败，则回滚事务
            return false;
        } catch (SQLException e) {
            if (conn != null) {
                try {
                    conn.rollback();  // 发生SQL异常时回滚事务
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            // 处理唯一键冲突的情况
            if (e.getErrorCode() == 1062) {  // 唯一键冲突错误码
                if (e.getMessage().contains("id_card")) {
                    JOptionPane.showMessageDialog(null, "该身份证号已存在！");
                } else if (e.getMessage().contains("student_no")) {
                    JOptionPane.showMessageDialog(null, "该学号已存在！");
                } else if (e.getMessage().contains("username")) {
                    JOptionPane.showMessageDialog(null, "该用户名已存在！");
                }
            }
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
            return false;
        } catch (Exception e) {
            throw new RuntimeException(e);  // 如果发生其他异常，则抛出运行时异常
        } finally {
            if (conn != null) {
                try {
                    conn.setAutoCommit(true);  // 关闭事务，恢复自动提交
                    conn.close();  // 关闭数据库连接
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 更新学生的信息，如果班级发生变化，则重新生成学号。
     *
     * @param student 学生对象，包含更新后的学生信息
     * @return 如果更新成功则返回true，否则返回false
     */
    public boolean updateStudent(Student student) {
        Connection conn = null;
        try {
            conn = DatabaseUtil.getConnection();  // 获取数据库连接
            conn.setAutoCommit(false);  // 开启事务

            // 获取原学生信息
            Student oldStudent = getStudentByStudentNo(student.getStudentNo());

            // 如果班级发生变化，需要重新生成学号
            if (oldStudent.getClassId() != student.getClassId()) {
                // 获取新班级的系部和专业信息
                String sql = "SELECT m.dept_code, m.major_code FROM classes c " +
                        "JOIN majors m ON c.major_code = m.major_code " +
                        "WHERE c.id = ?";

                try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                    pstmt.setInt(1, student.getClassId());
                    ResultSet rs = pstmt.executeQuery();

                    if (rs.next()) {
                        String deptCode = rs.getString("dept_code");  // 获取系部编号
                        String majorCode = rs.getString("major_code");  // 获取专业编号

                        // 生成新学号
                        String newStudentNo = generateStudentNo(
                                deptCode,
                                majorCode,
                                student.getClassId(),
                                student.getEnrollmentYear()
                        );
                        student.setStudentNo(newStudentNo);  // 设置新的学号

                        // 更新用户表中的用户名
                        String updateUserSql = "UPDATE users SET username = ? WHERE id = ?";
                        try (PreparedStatement userStmt = conn.prepareStatement(updateUserSql)) {
                            userStmt.setString(1, newStudentNo);  // 设置SQL语句中的参数username为新的学号
                            userStmt.setInt(2, student.getUserId());  // 设置SQL语句中的参数id为用户ID
                            userStmt.executeUpdate();  // 执行更新语句
                        }
                    }
                }
            }

            // 更新学生信息
            String updateSql = "UPDATE students SET name = ?, gender = ?, phone = ?, " +
                    "email = ?, birth_date = ?, home_address = ?, " +
                    "class_id = ?, status = ?, student_no = ? " +
                    "WHERE id = ?";

            try (PreparedStatement pstmt = conn.prepareStatement(updateSql)) {
                pstmt.setString(1, student.getName());  // 设置SQL语句中的参数name为学生的新姓名
                pstmt.setString(2, student.getGender());  // 设置SQL语句中的参数gender为学生的新性别
                pstmt.setString(3, student.getPhone());  // 设置SQL语句中的参数phone为学生的新电话
                pstmt.setString(4, student.getEmail());  // 设置SQL语句中的参数email为学生的新邮箱
                pstmt.setDate(5, new java.sql.Date(student.getBirthDate().getTime()));  // 设置SQL语句中的参数birth_date为学生的新出生日期
                pstmt.setString(6, student.getHomeAddress());  // 设置SQL语句中的参数home_address为学生的新家庭地址
                pstmt.setInt(7, student.getClassId());  // 设置SQL语句中的参数class_id为学生的新班级ID
                pstmt.setString(8, student.getStatus());  // 设置SQL语句中的参数status为学生的新状态
                pstmt.setString(9, student.getStudentNo());  // 设置SQL语句中的参数student_no为学生的新学号
                pstmt.setInt(10, student.getId());  // 设置SQL语句中的参数id为学生ID

                if (pstmt.executeUpdate() > 0) {  // 执行更新语句并检查受影响的行数
                    conn.commit();  // 如果更新成功，则提交事务
                    return true;
                }
            }

            conn.rollback();  // 如果更新失败，则回滚事务
            return false;
        } catch (SQLException e) {
            if (conn != null) {
                try {
                    conn.rollback();  // 发生SQL异常时回滚事务
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
            return false;
        } finally {
            if (conn != null) {
                try {
                    conn.setAutoCommit(true);  // 关闭事务，恢复自动提交
                    conn.close();  // 关闭数据库连接
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 添加生成学号的辅助方法
    /**
     * 根据系部编号、专业编号、班级ID和入学年份生成一个新的学号。
     *
     * @param deptCode 系部编号
     * @param majorCode 专业编号
     * @param classId 班级ID
     * @param enrollmentYear 入学年份
     * @return 新的学号
     */
    private String generateStudentNo(String deptCode, String majorCode, int classId, int enrollmentYear) {
        // 获取当前班级的最大序号
        int maxSeq = getMaxSequenceNumber(classId);  // 调用getMaxSequenceNumber方法获取当前班级的最大序号
        int nextSeq = maxSeq + 1;  // 计算下一个序号

        // 格式化学号
        return String.format("%d%02d%02d%02d%02d",
                enrollmentYear,                 // 入学年份(4位)
                Integer.parseInt(deptCode),     // 系部编号(2位)
                Integer.parseInt(majorCode),    // 专业编号(2位)
                classId % 100,                 // 班级号(2位)
                nextSeq                        // 序号(2位)
        );
    }

    /**
     * 更新学生的状态。
     *
     * @param studentNo 学号
     * @param status 学生状态
     * @return 如果更新成功则返回true，否则返回false
     */
    public boolean updateStudentStatus(String studentNo, String status) {
        String sql = "UPDATE students SET status = ? WHERE student_no = ?";  // SQL更新语句，更新students表中的学生状态

        try (Connection conn = DatabaseUtil.getConnection();  // 获取数据库连接
             PreparedStatement stmt = conn.prepareStatement(sql)) {  // 创建PreparedStatement对象用于执行SQL语句

            stmt.setString(1, status);  // 设置SQL语句中的参数status为新的学生状态
            stmt.setString(2, studentNo);  // 设置SQL语句中的参数student_no为学生的学号

            return stmt.executeUpdate() > 0;  // 执行更新语句并检查受影响的行数，大于0则返回true，否则返回false
        } catch (SQLException e) {
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
            return false;  // 返回false
        }
    }

    /**
     * 获取指定班级ID的最大序号，用于生成新的学号。
     *
     * @param classId 班级ID
     * @return 当前班级的最大序号
     */
    public int getMaxSequenceNumber(int classId) {
        String sql = "SELECT MAX(CAST(RIGHT(student_no, 2) AS SIGNED)) " +
                "FROM students WHERE class_id = ?";  // SQL查询语句，获取指定班级ID的最大序号

        try (Connection conn = DatabaseUtil.getConnection();  // 获取数据库连接
             PreparedStatement pstmt = conn.prepareStatement(sql)) {  // 创建PreparedStatement对象用于执行SQL语句

            pstmt.setInt(1, classId);  // 设置SQL语句中的参数class_id为指定的班级ID
            ResultSet rs = pstmt.executeQuery();  // 执行查询语句并获取结果集

            if (rs.next()) {
                return rs.getInt(1);  // 获取查询结果中的最大序号
            }
        } catch (SQLException e) {
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
        }
        return 0;  // 如果未找到记录，则返回0
    }

    /**
     * 根据学号获取学生的信息，包括学号、姓名、性别、身份证、家庭地址等，并关联班级名称。
     *
     * @param studentNo 学号
     * @return 学生信息对象，如果未找到则返回null
     */
    public Student getStudentByStudentNo(String studentNo) {
        String sql = "SELECT s.*, c.class_name FROM students s " +
                "LEFT JOIN classes c ON s.class_id = c.id " +
                "WHERE s.student_no = ?";  // SQL查询语句，根据student_no从students表中获取学生信息，并关联班级名称

        try (Connection conn = DatabaseUtil.getConnection();  // 获取数据库连接
             PreparedStatement stmt = conn.prepareStatement(sql)) {  // 创建PreparedStatement对象用于执行SQL语句

            stmt.setString(1, studentNo);  // 设置SQL语句中的参数student_no为指定的学号
            ResultSet rs = stmt.executeQuery();  // 执行查询语句并获取结果集

            if (rs.next()) {  // 如果查询结果中有一行数据
                Student student = new Student();  // 创建一个新的Student对象用于存储当前行的数据

                // 将结果集中的每一列数据设置到Student对象中
                student.setId(rs.getInt("id"));
                student.setStudentNo(rs.getString("student_no"));
                student.setName(rs.getString("name"));
                student.setIdCard(rs.getString("id_card"));
                student.setGender(rs.getString("gender"));

                // 如果class_id不为null，则设置class_id，否则设置为0
                Object classIdObj = rs.getObject("class_id");
                student.setClassId(classIdObj != null ? rs.getInt("class_id") : 0);

                student.setClassName(rs.getString("class_name"));
                student.setEnrollmentYear(rs.getInt("enrollment_year"));
                student.setPhone(rs.getString("phone"));
                student.setEmail(rs.getString("email"));
                student.setBirthDate(rs.getDate("birth_date"));
                student.setHomeAddress(rs.getString("home_address"));
                student.setStatus(rs.getString("status"));

                return student;  // 返回填充好的Student对象
            }
        } catch (SQLException e) {
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
        }
        return null;  // 如果未找到学生信息，则返回null
    }

    /**
     * 根据学号删除一个学生。
     *
     * @param studentNo 学号
     * @return 如果删除成功则返回true，否则返回false
     */
    public boolean deleteStudentByStudentNo(String studentNo) {
        String sql = "DELETE FROM students WHERE student_no = ?";  // SQL删除语句，根据student_no从students表中删除学生

        try (Connection conn = DatabaseUtil.getConnection();  // 获取数据库连接
             PreparedStatement stmt = conn.prepareStatement(sql)) {  // 创建PreparedStatement对象用于执行SQL语句

            stmt.setString(1, studentNo);  // 设置SQL语句中的参数student_no为指定的学号
            return stmt.executeUpdate() > 0;  // 执行删除语句并检查受影响的行数，大于0则返回true，否则返回false
        } catch (SQLException e) {
            e.printStackTrace();  // 如果发生SQL异常，则打印堆栈跟踪信息
            return false;  // 返回false
        }
    }
}
